package com.bj.disc.ui.login.utils

import com.ai3d.rfid.common.log.Logcat
import com.ai3d.rfid.common.log.Logcat.d
import com.ai3d.rfid.common.log.Logcat.e
import com.ai3d.rfid.common.proxy.MMKVProxy
import java.io.*
import java.nio.ByteBuffer
import java.nio.channels.FileChannel
import java.nio.channels.FileLock
import java.util.zip.ZipInputStream


/**
 * @ProjectName : Trias
 * @Author : weijinsong
 * @Time : 2022/10/27 15:18
 * @Description : 文件工具类
 *
 *
 * FileUtils.saveShareFile(
 * ByteArrayInputStream(it?.showSvg?.toByteArray()),
 * App.instance.filesDir.absolutePath , "2.svg")
 */
object FileUtils {
    private const val TAG = "FileUtils"
    fun saveShareFile(
        inputStream: InputStream,
        dir: String,
        fileName: String,
        length:Long,
        isContinuation: Boolean = false,
        callBack: (() -> Unit)? = null
    ): String? {
        var pathName = ""
        d(TAG, "")
        pathName = if (isExitDir(dir)) {
            dir + fileName
        } else {
            return null
        }
        val saveFile = File(pathName)
        // 随机访问文件，可以指定断点续传的起始位置
        // 随机访问文件，可以指定断点续传的起始位置
        d(TAG, "saveShareFile pathName : $pathName")
        var channelOut: FileChannel? = null
        // 随机访问文件，可以指定断点续传的起始位置
        // 随机访问文件，可以指定断点续传的起始位置
        var randomAccessFile: RandomAccessFile? = null
        var fileLock: FileLock?=null
        try {
            if (!saveFile.exists()) {
                saveFile.createNewFile()
            }
            //文件输出流
//            val outputStream = FileOutputStream(saveFile, isContinuation)
//            val bufferSize = 1024
//            val buff = ByteArray(bufferSize)
//            var rc = 0
//            var length = MMKVProxy.getLong(MMKVProxy.KEY_STATIC_ZIP_FILE_LENGTH)
//            if (!isContinuation){//续传
//                MMKVProxy.setLong(KEY_DOWNLOAD_FILE_START_POSITION,0)
//            }else{
//                length = MMKVProxy.getLong(KEY_DOWNLOAD_FILE_START_POSITION,0)
//            }
//            var startPosition = MMKVProxy.getLong(KEY_DOWNLOAD_FILE_START_POSITION,0)



            try {
                randomAccessFile = RandomAccessFile(saveFile, "rwd")
//                //Chanel NIO中的用法，由于RandomAccessFile没有使用缓存策略，直接使用会使得下载速度变慢，亲测缓存下载3.3秒的文件，用普通的RandomAccessFile需要20多秒。
//                //Chanel NIO中的用法，由于RandomAccessFile没有使用缓存策略，直接使用会使得下载速度变慢，亲测缓存下载3.3秒的文件，用普通的RandomAccessFile需要20多秒。
                channelOut = randomAccessFile!!.channel
//                // 内存映射，直接使用RandomAccessFile，是用其seek方法指定下载的起始位置，使用缓存下载，在这里指定下载位置。
//                // 内存映射，直接使用RandomAccessFile，是用其seek方法指定下载的起始位置，使用缓存下载，在这里指定下载位置。
//                val mappedBuffer = channelOut.map(
//                    FileChannel.MapMode.READ_WRITE,
//                    MMKVProxy.getLong(MMKVProxy.KEY_DOWNLOAD_FILE_FINISH_LENGTH,0L),
//                    length
//                )
                randomAccessFile.seek(MMKVProxy.getLong(MMKVProxy.KEY_DOWNLOAD_FILE_FINISH_LENGTH,0L)) // Move the file pointer to the last downloaded position

                val fileChannel = randomAccessFile.channel
                fileLock= fileChannel.lock()
                val buffer = ByteArray(2*1024)
                var bytesRead: Int

                inputStream?.use { input ->
                    while (input.read(buffer).also { bytesRead = it } != -1) {
                        val byteBuffer = ByteBuffer.wrap(buffer, 0, bytesRead)
                        fileChannel.write(byteBuffer) // Write the buffer to the file
                    }
                }
//                while (inputStream.read(buff, 0, bufferSize).also { rc = it } > 0) {
//                    outputStream.write(buff, 0, rc)
//                    outputStream.flush()
//                    callBack?.invoke()
//                }
//
//                outputStream.close()
//                inputStream.close()
//                channelOut.close()
//                randomAccessFile.close()
                d(TAG, "saveShareFile  pathName : $pathName")
            } catch (e: IOException) {
                e.printStackTrace()
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        finally {
            fileLock?.release()
            inputStream.close()
            channelOut?.close()
            randomAccessFile?.close()
        }
        d(TAG, "saveShareFile  absolutePath : " + saveFile.absolutePath)
        return saveFile.absolutePath
    }

    private fun isExitDir(path: String): Boolean {
        val file = File(path)
        if (!file.exists()) {
            file.mkdir()
        }
        createFile(path)
        return true
    }

    private fun createFile(path: String?): File? {
        try {
            val dir = File(path)
            if (dir.isFile) return null
            if (dir.exists()) {
                val file = File(path, "path")
                file.createNewFile()
                return file
            }
        } catch (tr: Throwable) {
            e("createFile", tr.message)
            return null
        }
        return null
    }

    /**
     * zipPath 文件真实路径 /data/user/0/com.bj.disc/files/static.zip
     * outputDirectory 转移目录 /data/user/0/com.bj.disc/files/
     */
    fun unzipFile(zipPath: String, outputDirectory: String, callBack: (() -> Unit)? = null) {
        /**
         * 解压assets的zip压缩文件到指定目录
         * @param context上下文对象
         * @param assetName压缩文件名
         * @param outputDirectory输出目录
         * @param isReWrite是否覆盖
         * @throws IOException
         */
        Logcat.d(TAG, "开始解压的文件： $zipPath\n解压的目标路径：$outputDirectory")
        // 创建解压目标目录
        var file = File(outputDirectory)
        // 如果目标目录不存在，则创建
        if (!file.exists()) {
            file.mkdirs()
        }
        // 打开压缩文件
        val inputStream: InputStream = FileInputStream(zipPath)
        val zipInputStream = ZipInputStream(inputStream)

        // 读取一个进入点
        var zipEntry = zipInputStream.nextEntry
        // 使用1Mbuffer
        val buffer = ByteArray(1024 * 1024)
        // 解压时字节计数
        var count = 0
        try {
            // 如果进入点为空说明已经遍历完所有压缩包中文件和目录
            while (zipEntry != null) {
//                Logcat.d(TAG, "解压文件 入口 1： $zipEntry")
                if (!zipEntry.isDirectory) {  //如果是一个文件
                    // 如果是文件
                    var fileName = zipEntry.name
                    Logcat.d(TAG, "解压文件 原来 文件的位置： $fileName")
                    fileName = fileName.substring(fileName.lastIndexOf("/") + 1) //截取文件的名字 去掉原文件夹名字
                    var dirPath =
                        zipEntry.name.substring(
                            0,
                            zipEntry.name.lastIndexOf("/") + 1
                        ) //截取文件的名字 去掉原文件夹名字

                    var fileNames = dirPath.split("/")
                    Logcat.d(TAG, " dirPath : $dirPath fileName : $fileName")
                    var tempFilePath = ""
                    fileNames.forEach {
                        tempFilePath = tempFilePath + File.separator + it
                        var tempFile =
                            File(outputDirectory + File.separator + tempFilePath) //放到新的解压的文件夹
                        if (!tempFile.exists()) {
                            tempFile.mkdir()
                            Logcat.d(
                                TAG,
                                "tempFilePath $tempFilePath 创建文件夹结果 : ${tempFile.mkdir()}"
                            )
                        }
                    }
                    var file =
                        File(outputDirectory + File.separator + tempFilePath + File.separator + fileName) //放到新的解压的文件路径

                    Logcat.d(
                        TAG,
                        " 解压文件 的名字： $fileName dirPath : $dirPath  file abs : ${file.absolutePath}"
                    )

                    file.createNewFile()
                    val fileOutputStream = FileOutputStream(file)
                    while (zipInputStream.read(buffer).also { count = it } > 0) {
                        fileOutputStream.write(buffer, 0, count)
                    }
                    fileOutputStream.close()
                }

                // 定位到下一个文件入口
                zipEntry = zipInputStream.nextEntry
//                Logcat.d(TAG, "解压文件 入口 2： $zipEntry")
            }
            zipInputStream.close()
            Logcat.d(TAG, "解压完成")
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            callBack?.invoke()
        }
    }

}